package com.kingzoder.food.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kingzoder.food.common.AppHttpCode;
import com.kingzoder.food.common.base.ResultVO;
import com.kingzoder.food.common.base.page.PageHelper;
import com.kingzoder.food.common.base.page.PageResultVO;
import com.kingzoder.food.common.utils.BeanCopyUtils;
import com.kingzoder.food.exception.RRException;
import com.kingzoder.food.mapper.IngredientMapper;
import com.kingzoder.food.mapper.RecipeMapper;
import com.kingzoder.food.mapper.RecipeStepMapper;
import com.kingzoder.food.model.dto.ingredient.EditIngredientDTO;
import com.kingzoder.food.model.dto.ingredient.EditRecipeStepDTO;
import com.kingzoder.food.model.dto.ingredient.IngredientDTO;
import com.kingzoder.food.model.dto.ingredient.RecipeStepDTO;
import com.kingzoder.food.model.dto.recipe.AddRecipeDTO;
import com.kingzoder.food.model.dto.recipe.EditRecipeDTO;
import com.kingzoder.food.model.dto.recipe.SearchRecipeDTO;
import com.kingzoder.food.model.entity.Ingredient;
import com.kingzoder.food.model.entity.Recipe;
import com.kingzoder.food.model.entity.RecipeStep;
import com.kingzoder.food.model.vo.IngredientVO;
import com.kingzoder.food.model.vo.RecipeStepVO;
import com.kingzoder.food.model.vo.recipe.RecipeDetailVO;
import com.kingzoder.food.model.vo.recipe.RecipeVO;
import com.kingzoder.food.service.RecipeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author ZoderKing
 */
@Service
@RequiredArgsConstructor
public class RecipeServiceImpl extends ServiceImpl<RecipeMapper, Recipe> implements RecipeService {
    private final RecipeMapper recipeMapper;
    private final IngredientMapper ingredientMapper;
    private final RecipeStepMapper recipeStepMapper;

    @Override
    public PageResultVO<List<RecipeVO>> queryPage(SearchRecipeDTO queryDTO) {
        PageResultVO<List<RecipeVO>> pageResultVO = new PageResultVO<>(queryDTO);
        LambdaQueryWrapper<Recipe> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Recipe::getId, Recipe::getTitle, Recipe::getDescription,
                Recipe::getCookTime, Recipe::getImageUrl);
        Page<Recipe> page = PageHelper.convertPageByQuery(queryDTO);
        Page<Recipe> result = recipeMapper.selectPage(page, queryWrapper);
        List<RecipeVO> recipeVOS = BeanCopyUtils.copyBeanList(result.getRecords(), RecipeVO.class);
        pageResultVO.setData(recipeVOS);
        pageResultVO.setTotalCount(result.getTotal());
        return pageResultVO;
    }

    @Override
    public ResultVO<RecipeDetailVO> queryOne(Long id) {
        Recipe recipe = getById(id);
        RecipeDetailVO detailVO = BeanCopyUtils.copyBean(recipe, RecipeDetailVO.class);
        // 查询食材
        LambdaQueryWrapper<Ingredient> ingredientQueryWrapper = new LambdaQueryWrapper<>();
        ingredientQueryWrapper.eq(Ingredient::getRecipeId, recipe.getId());
        List<Ingredient> ingredients = ingredientMapper.selectList(ingredientQueryWrapper);
        detailVO.setIngredients(BeanCopyUtils.copyBeanList(ingredients, IngredientVO.class));
        // 查询制作步骤
        LambdaQueryWrapper<RecipeStep> recipeQueryWrapper = new LambdaQueryWrapper<>();
        recipeQueryWrapper.eq(RecipeStep::getRecipeId, recipe.getId());
        List<RecipeStep> recipeSteps = recipeStepMapper.selectList(recipeQueryWrapper);
        detailVO.setSteps(BeanCopyUtils.copyBeanList(recipeSteps, RecipeStepVO.class));
        return ResultVO.success(detailVO);
    }

    @Transactional
    @Override
    public ResultVO<Boolean> add(AddRecipeDTO addDTO) {
        Recipe recipe = BeanCopyUtils.copyBean(addDTO, Recipe.class);
        boolean success = save(recipe);
        if (!success) {
            throw new RRException(AppHttpCode.ERROR_PARAM);
        }
        // 添加食材
        List<IngredientDTO> ingredientDTOS = addDTO.getIngredients();
        List<Ingredient> ingredients = ingredientDTOS.stream().map(e -> {
            Ingredient ingredient = BeanCopyUtils.copyBean(e, Ingredient.class);
            ingredient.setRecipeId(recipe.getId());
            return ingredient;
        }).toList();
        // 添加制作步骤
        List<RecipeStepDTO> stepDTOS = addDTO.getSteps();
        List<RecipeStep> steps = stepDTOS.stream().map(e -> {
            RecipeStep recipeStep = BeanCopyUtils.copyBean(e, RecipeStep.class);
            recipeStep.setRecipeId(recipe.getId());
            return recipeStep;
        }).toList();
        ingredientMapper.insertBatchSomeColumn(ingredients);
        recipeStepMapper.insertBatchSomeColumn(steps);
        return ResultVO.success(true);
    }

    @Transactional
    @Override
    public ResultVO<Boolean> edit(EditRecipeDTO updateDTO) {
        Recipe recipe = BeanCopyUtils.copyBean(updateDTO, Recipe.class);
        boolean success = updateById(recipe);
        if (!success) {
            throw new RRException(AppHttpCode.ERROR_PARAM);
        }
        List<EditIngredientDTO> ingredientDTOS = updateDTO.getIngredients();
        List<EditRecipeStepDTO> stepDTOS = updateDTO.getSteps();
        List<Ingredient> ingredients = BeanCopyUtils.copyBeanList(ingredientDTOS, Ingredient.class);
        List<RecipeStep> steps = BeanCopyUtils.copyBeanList(stepDTOS, RecipeStep.class);
        ingredientMapper.updateById(ingredients);
        recipeStepMapper.updateById(steps);
        return ResultVO.success(true);
    }

    @Transactional
    @Override
    public ResultVO<Boolean> remove(Long id) {
        boolean success = removeById(id);
        if (!success) {
            throw new RRException(AppHttpCode.ERROR_PARAM);
        }
        // 删除关联数据
        LambdaQueryWrapper<Ingredient> ingredientQueryWrapper = new LambdaQueryWrapper<>();
        ingredientQueryWrapper.eq(Ingredient::getRecipeId, id);
        ingredientMapper.delete(ingredientQueryWrapper);
        LambdaQueryWrapper<RecipeStep> recipeQueryWrapper = new LambdaQueryWrapper<>();
        recipeQueryWrapper.eq(RecipeStep::getRecipeId, id);
        recipeStepMapper.delete(recipeQueryWrapper);
        return ResultVO.success(true);
    }
}
